//update this file by ZRH latest issue to solve the order tax
/******************************************************************************
 * Product: Adempiere ERP & CRM Smart Business Solution                       *
 * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved.                *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA        *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.inspire.model;

import java.math.BigDecimal;

import java.math.RoundingMode;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Level;

import org.compiere.acct.Doc;
import org.compiere.acct.DocLine;
import org.compiere.acct.DocTax;
import org.compiere.acct.Fact;
import org.compiere.acct.FactLine;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MAllocationHdr;
import org.compiere.model.MAllocationLine;
import org.compiere.model.MBPartner;
import org.compiere.model.MClient;
import org.compiere.model.MDocType;
import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MInvoicePaySchedule;
import org.compiere.model.MInvoiceTax;
import org.compiere.model.MOrderLine;
import org.compiere.model.MPayment;
import org.compiere.model.MPaymentAllocate;
import org.compiere.model.MPaymentTerm;
import org.compiere.model.MTax;
import org.compiere.model.ModelValidationEngine;
import org.compiere.model.ModelValidator;
import org.compiere.model.PO;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.inspire.model.X_INS_OrderTax;

/**
 *	Validator or Localization Colombia (Withholdings)
 *	
 *  @author Carlos Ruiz - globalqss - Quality Systems & Solutions - http://globalqss.com 
 *	@version $Id: LCO_Validator.java,v 1.4 2007/05/13 06:53:26 cruiz Exp $
 */
public class INS_Validator implements ModelValidator
{
	/**
	 *	Constructor.
	 *	The class is instantiated when logging in and client is selected/known
	 */
	public INS_Validator ()
	{
		super ();
	}	//	MyValidator
	
	/**	Logger			*/
	private static CLogger log = CLogger.getCLogger(INS_Validator.class);
	/** Client			*/
	private int		m_AD_Client_ID = -1;
	
	/**
	 *	Initialize Validation
	 *	@param engine validation engine 
	 *	@param client client
	 */
	public void initialize (ModelValidationEngine engine, MClient client)
	{
		//client = null for global validator
		if (client != null) {	
			m_AD_Client_ID = client.getAD_Client_ID();
			log.info(client.toString());
		}
		else  {
			log.info("Initializing global validator: "+this.toString());
		}

		engine.addDocValidate(MAllocationHdr.Table_Name, this);
		engine.addDocValidate(MPayment.Table_Name, this);
		
		engine.addModelChange(MOrderLine.Table_Name, this);
		engine.addModelChange(MInvoiceLine.Table_Name, this);		

	}	//	initialize

    /**
     *	Model Change of a monitored Table.
     *	Called after PO.beforeSave/PO.beforeDelete
     *	when you called addModelChange for the table
     *	@param po persistent object
     *	@param type TYPE_
     *	@return error message or null
     *	@exception Exception if the recipient wishes the change to be not accept.
     */
	public String modelChange (PO po, int type) throws Exception
	{
		log.info(po.get_TableName() + " Type: "+type);
		String msg;
		String msg1;

		if (po.get_TableName().equals(MOrderLine.Table_Name) && ( type==TYPE_AFTER_NEW || type==TYPE_AFTER_CHANGE) ) {
			msg = insertOrderLineTax( po.getCtx(), (MOrderLine) po );		
			if (msg != null)
				return msg;
		}		

		if (po.get_TableName().equals(MInvoiceLine.Table_Name) && ( type==TYPE_AFTER_NEW || type==TYPE_AFTER_CHANGE) ) {
			msg = insertInvoiceLineTax( po.getCtx(), (MInvoiceLine) po );
			msg1 = deleteInvoiceLineZero( po.getCtx(), (MInvoiceLine) po );
			
			if (msg != null)
				return msg;
			
			if (msg1 != null)
				return msg1;			
		}		
		

		return null;
	}	//	modelChange
	

	/**
	 *	Validate Document.
	 *	Called as first step of DocAction.prepareIt 
     *	when you called addDocValidate for the table.
     *	Note that totals, etc. may not be correct.
	 *	@param po persistent object
	 *	@param timing see TIMING_ constants
     *	@return error message or null
	 */
	public String docValidate (PO po, int timing)
	{
		log.info(po.get_TableName() + " Timing: "+timing);
		String msg;

		// before posting the allocation - post the payment withholdings vs writeoff amount  
		if (po.get_TableName().equals(MAllocationHdr.Table_Name) && timing == TIMING_BEFORE_POST) {
			msg = accountingForPaymentWithholding((MAllocationHdr) po);
			if (msg != null)
				return msg;
		}
		
		if (po.get_TableName().equals(MPayment.Table_Name) && timing == TIMING_BEFORE_POST) {
			msg = accountingForPrePaymentWithholding((MPayment) po);
			if (msg != null)
				return msg;
		}

		if (po.get_TableName().equals(MOrderLine.Table_Name) && timing == TIMING_AFTER_PREPARE) {
			msg = insertOrderLineTax( po.getCtx(), (MOrderLine) po );
			if (msg != null)
				return msg;
		}

		
		return null;
	}	//	docValidate

	
	private String accountingForPaymentWithholding(MAllocationHdr ah) {
	
		// Accounting like Doc_Allocation
		// 20070807 - globalqss - instead of adding a new WriteOff post, find the
		//  current WriteOff and subtract from the posting
		// Customised by Zulqarnain Habib (Project Inspire-Systems Automation) 17-Feb-11
		
	//	if (1==1){return "";}
		
		Doc doc = ah.getDoc();
		
		ArrayList<Fact> facts = doc.getFacts();
		// one fact per acctschema
		
		for (int i = 0; i < facts.size(); i++)
		{
			Fact fact = facts.get(i);
			MAcctSchema as = fact.getAcctSchema();
			
			MAllocationLine[] alloc_lines = ah.getLines(false);
			for (int j = 0; j < alloc_lines.length; j++) {
				BigDecimal tottax = new BigDecimal(0);
				
				MAllocationLine alloc_line = alloc_lines[j];
				doc.setC_BPartner_ID(alloc_line.getC_BPartner_ID());
				
				MInvoice invoice = null;

				String sql = 
					  "SELECT i.C_Tax_ID, NVL(SUM(i.Amount),0)  AS TaxAmt, t.Name, t.Rate "
					 + " FROM C_Payment p, C_PaymentAllocate pa, INS_PaymentTax i, C_Tax t "
					+ " WHERE p.C_Payment_ID = ? AND " +
							"p.C_Payment_ID = pa.C_Payment_ID AND " +
							"pa.C_PaymentAllocate_ID = i.C_PaymentAllocate_ID AND " +
							 "i.C_Tax_ID = t.C_Tax_ID "
					+ "GROUP BY i.C_Tax_ID, t.Name, t.Rate";
				
				PreparedStatement pstmt = null;
				ResultSet rs = null;
				try
				{
					pstmt = DB.prepareStatement(sql, ah.get_TrxName());
					pstmt.setInt(1, alloc_line.getC_Payment_ID());
					rs = pstmt.executeQuery();
					while (rs.next()) {
						int tax_ID = rs.getInt(1);
						BigDecimal amount = rs.getBigDecimal(2);
						String name = rs.getString(3);
						BigDecimal rate = rs.getBigDecimal(4);
						
						
						DocTax taxLine = new DocTax(tax_ID, name, rate, 
								Env.ZERO, amount, false);
						
						if (amount != null && amount.signum() != 0)
						{
							FactLine tl = null;
							if ( alloc_line.getC_Payment().isReceipt() )
								tl = fact.createLine(null, taxLine.getAccount(DocTax.ACCTTYPE_TaxDue, as),
										as.getC_Currency_ID(), amount, null);
							else
								
								tl = fact.createLine(null, taxLine.getAccount(DocTax.ACCTTYPE_TaxDue, as),
										as.getC_Currency_ID(), null, amount);

							if (tl != null)
								tl.setC_Tax_ID(taxLine.getC_Tax_ID());
							tottax = tottax.add(amount);
						}
					}
				} catch (Exception e) {
					log.log(Level.SEVERE, sql, e);
					return "Error posting INS_PaymentTax from INS_Validator";
				} finally {
					DB.close(rs, pstmt);
					rs = null; pstmt = null;
				}
				
				//	Write off		DR
				if (Env.ZERO.compareTo(tottax) != 0)
				{
					// First try to find the WriteOff posting record
					FactLine[] factlines = fact.getLines();

					for (int ifl = 0; ifl < factlines.length; ifl++) {
						FactLine fl = factlines[ifl];
						if (fl.getAccount().equals(doc.getAccount(Doc.ACCTTYPE_WriteOff, as))) {

								BigDecimal balamt = fl.getAmtSourceDr().subtract(fl.getAmtSourceCr());
								BigDecimal newbalamt = Env.ZERO;

								if ( alloc_line.getC_Payment().isReceipt() )
								{
									newbalamt = balamt.subtract(tottax);
								}
								else						
								{
									newbalamt = balamt.add(tottax);
								}
								
								
								if (Env.ZERO.compareTo(newbalamt) == 0) {
								// both zeros, remove the line
								fact.remove(fl);
							} else if (Env.ZERO.compareTo(newbalamt) > 0) {
								fl.setAmtAcct(fl.getC_Currency_ID(), Env.ZERO, newbalamt);
								fl.setAmtSource(fl.getC_Currency_ID(), Env.ZERO, newbalamt);
							} else {
								fl.setAmtAcct(fl.getC_Currency_ID(), newbalamt, Env.ZERO);
								fl.setAmtSource(fl.getC_Currency_ID(), newbalamt, Env.ZERO);
							}
							break;
						}
					}
				}
				
			}

		}

		return null;
	}


	private String accountingForPrePaymentWithholding(MPayment pp) {
		// Accounting like Doc_Allocation
		// 20070807 - globalqss - instead of adding a new WriteOff post, find the
		//  current WriteOff and subtract from the posting
		// Customised by Zulqarnain Habib (Project Inspire-Systems Automation) 17-Feb-11
		
		// Exit if not Pre-Payment
		if (!pp.isPrepayment() && pp.getC_Charge_ID()==0) //use for both cases prepayment as well as charge payment updated by ARH
			return "";
		
		Doc doc = pp.getDoc();
		
		ArrayList<Fact> facts = doc.getFacts();
		// one fact per acctschema
		for (int i = 0; i < facts.size(); i++)
		{
			Fact fact = facts.get(i);
			MAcctSchema as = fact.getAcctSchema();
			
				BigDecimal tottax = new BigDecimal(0);
				
				doc.setC_BPartner_ID(pp.getC_BPartner_ID());
				
				String sql = 
					  "SELECT i.C_Tax_ID, NVL(SUM(i.Amount),0)  AS TaxAmt, t.Name, t.Rate "
					 + " FROM C_Payment p, INS_PaymentTax i, C_Tax t "
					+ " WHERE p.C_Payment_ID = ? AND " +
							"p.C_Payment_ID = i.C_Payment_ID AND " +
							 "i.C_Tax_ID = t.C_Tax_ID "
					+ "GROUP BY i.C_Tax_ID, t.Name, t.Rate";
				
				PreparedStatement pstmt = null;
				ResultSet rs = null;
				try
				{
					pstmt = DB.prepareStatement(sql, pp.get_TrxName());
					pstmt.setInt(1, pp.getC_Payment_ID());
					rs = pstmt.executeQuery();
					while (rs.next()) {
						int tax_ID = rs.getInt(1);
						BigDecimal amount = rs.getBigDecimal(2);
						String name = rs.getString(3);
						BigDecimal rate = rs.getBigDecimal(4);
						
						
						DocTax taxLine = new DocTax(tax_ID, name, rate, 
								Env.ZERO, amount, false);
						
						if (amount != null && amount.signum() != 0)
						{

							FactLine tl = null;
							
							if (pp.isReceipt() || amount.signum() == -1)
								tl = fact.createLine(null, taxLine.getAccount(DocTax.ACCTTYPE_TaxDue, as),
										as.getC_Currency_ID(), amount.abs(), null);
							else
								
								tl = fact.createLine(null, taxLine.getAccount(DocTax.ACCTTYPE_TaxDue, as),
										as.getC_Currency_ID(), null, amount);

							if (tl != null)
								tl.setC_Tax_ID(taxLine.getC_Tax_ID());
							tottax = tottax.add(amount);
						}
					}
				} catch (Exception e) {
					log.log(Level.SEVERE, sql, e);
					return "Error posting INS_Pre-PaymentTax from INS_Validator";
				} finally {
					DB.close(rs, pstmt);
					rs = null; pstmt = null;
				}
				
				//	Write off		DR
				if (Env.ZERO.compareTo(tottax) != 0)
				{
					// First try to find the WriteOff posting record
					FactLine[] factlines = fact.getLines();
					
					for (int ifl = 0; ifl < factlines.length; ifl++) {
						FactLine fl = factlines[ifl];
						if (fl.getAccount().equals(doc.getAccount(Doc.ACCTTYPE_BankInTransit, as))) {

							BigDecimal balamt = Env.ZERO;
							BigDecimal newbalamt = Env.ZERO;

							balamt = fl.getAmtSourceDr().subtract(fl.getAmtSourceCr());

							if (pp.isReceipt())
							{
								newbalamt = balamt.subtract(tottax);
							}
							else						
							{
								newbalamt = balamt.add(tottax);
							}
							

							if (Env.ZERO.compareTo(newbalamt) == 0) {
								// both zeros, remove the line
								fact.remove(fl);
							} else if (Env.ZERO.compareTo(newbalamt) > 0) {
								fl.setAmtAcct(fl.getC_Currency_ID(), Env.ZERO, newbalamt.negate());
								fl.setAmtSource(fl.getC_Currency_ID(), Env.ZERO, newbalamt.negate());
							} else {
								fl.setAmtAcct(fl.getC_Currency_ID(), newbalamt, Env.ZERO);
								fl.setAmtSource(fl.getC_Currency_ID(), newbalamt, Env.ZERO);
							}
							break;
						}
					}
				}
				
			}

		return null;
	}
	
	
	/**
	 *	User Login.
	 *	Called when preferences are set
	 *	@param AD_Org_ID org
	 *	@param AD_Role_ID role
	 *	@param AD_User_ID user
	 *	@return error message or null
	 */
	public String login (int AD_Org_ID, int AD_Role_ID, int AD_User_ID)
	{
		log.info("AD_User_ID=" + AD_User_ID);
		return null;
	}	//	login

	
	/**
	 *	Get Client to be monitored
	 *	@return AD_Client_ID client
	 */
	public int getAD_Client_ID()
	{
		return m_AD_Client_ID;
	}	//	getAD_Client_ID

	
	/**
	 * 	String Representation
	 *	@return info
	 */
	public String toString ()
	{
		StringBuffer sb = new StringBuffer ("INS_Validator");
		return sb.toString ();
	}	//	toString
	

	public String insertOrderLineTax(Properties ctx, MOrderLine ol)
	{

		
		int TaxId = ol.getC_Tax_ID();		
		BigDecimal LineAmt = ol.getLineNetAmt();

		MTax tax = new MTax (ctx, TaxId, null);
		BigDecimal TaxAmt = tax.calculateTax( LineAmt, false, 2);
		
		//Delete old child entries
		
		String sqlDelete = "DELETE Ins_OrderTax " +
				"WHERE C_OrderLine_Id=" + ol.getC_OrderLine_ID();
		
		DB.executeUpdate(sqlDelete, ol.get_TrxName());

		//Inserting a new tax

		//Exit if TaxAmt is 0
		//if (TaxAmt.equals(Env.ZERO)) //edited by ARH no need of this code because in case of zero tax we should update tax amount
			//return null;
		
		String sql = "SELECT COUNT(*) FROM C_TAX " +
				"WHERE Parent_Tax_Id = ?";
		int IsParent = DB.getSQLValue(ol.get_TrxName(), sql, TaxId);

		

		if (IsParent == 0) // It has No Childs
		{
			//Inserting new records
			X_INS_OrderTax OrderTax = new X_INS_OrderTax(ol.getCtx(), null, ol.get_TrxName());
			OrderTax.setC_Order_ID(ol.getC_Order_ID());
			OrderTax.setC_OrderLine_ID(ol.getC_OrderLine_ID());
			OrderTax.setC_Tax_ID(TaxId);
			OrderTax.setTaxAmt( TaxAmt );

			OrderTax.save();
			
			//Update C_OrderLine
			
			String sqlUpdateOrderLine = "UPDATE C_OrderLine SET C_Tax_Id1=" + TaxId +
					", Tax_Per1=" + ol.getC_Tax().getRate() +
					", TaxAmt1=" + TaxAmt +
					", C_Tax_Id2= null"  +
					", Tax_Per2= null"  +
					", TaxAmt2= 0"  +
					", C_Tax_Id3= null" +
					", Tax_Per3= null"  +
					", TaxAmt3= 0"  +
					" WHERE C_OrderLine_Id=" + ol.getC_OrderLine_ID();

			DB.executeUpdate(sqlUpdateOrderLine, ol.get_TrxName());

			
		}		

		else // Tax is Parent
		{
			String sqlParent = "Select  T.C_Tax_Id, T.Rate " +
							"From C_Tax T " +
							"Where Parent_Tax_Id=?" +
							"Order By T.Rate Desc";

			PreparedStatement pstmt = null;
			ResultSet rs = null;
			try
			{
				pstmt = DB.prepareStatement(sqlParent, ol.get_TrxName());
				
				pstmt.setInt(1, TaxId);
				rs = pstmt.executeQuery();
				int Counter = 0;
				while (rs.next())
				{
					Counter ++;
					
					//BigDecimal PaymentTotal = rs.getBigDecimal(1);		//	Total Payment Amount
					MTax m_tax = new MTax(ctx, TaxId, ol.get_TrxName());
					BigDecimal TotalTaxPercent = m_tax.getRate();
					BigDecimal ThisTaxRate	= (BigDecimal) rs.getBigDecimal(2);
					BigDecimal ThisTaxRatio = ThisTaxRate.divide(TotalTaxPercent, 2, RoundingMode.HALF_UP);
					BigDecimal ThisTaxAmount = TaxAmt.multiply(ThisTaxRatio);
					int thisTaxId = rs.getInt(1);

					//Inserting new records
					X_INS_OrderTax OrderTax = new X_INS_OrderTax(ol.getCtx(), null, ol.get_TrxName());
					OrderTax.setC_Order_ID(ol.getC_Order_ID());
					OrderTax.setC_OrderLine_ID(ol.getC_OrderLine_ID());
					OrderTax.setC_Tax_ID(rs.getInt(1));
					OrderTax.setTaxAmt( ThisTaxAmount );
					OrderTax.save();
					
					//Update C_OrderLine
					//This will crash if there are more than 3 taxes therefore just updating first 3 taxes in C_OrderLine
					if (Counter <=3)
					{
						String sqlUpdateOrderLine = "UPDATE C_OrderLine SET " +
						"C_Tax_Id" + Counter + "=" + thisTaxId +
						", Tax_Per" + Counter + "=" + ThisTaxRate +
						", TaxAmt" + Counter + "=" + ThisTaxAmount +
						" WHERE C_OrderLine_Id=" + ol.getC_OrderLine_ID();

				DB.executeUpdate(sqlUpdateOrderLine, ol.get_TrxName());
					
					}
					
				} //while
				
			} //try
		
				catch (SQLException e)
				{
					log.log(Level.SEVERE, sqlParent, e);
					return null;
				} //catch
				finally
				{
					DB.close(rs, pstmt);
					rs = null; pstmt = null;
				}//finally							
		
		
						
		} //else if	
			
		return null;
		
	} //Method

	public String insertInvoiceLineTax(Properties ctx, MInvoiceLine il)
	{

		
		int TaxId = il.getC_Tax_ID();

		if (TaxId == 0) {return null;}

		BigDecimal LineAmt = il.getLineNetAmt();

		MTax tax = new MTax (ctx, TaxId, null);
		BigDecimal TaxAmt = tax.calculateTax( LineAmt, false, 2);
		
		//Delete old child entries
		
		String sqlDelete = "DELETE Ins_InvoiceTax " +
				"WHERE C_InvoiceLine_Id=" + il.getC_InvoiceLine_ID();
		
		DB.executeUpdate(sqlDelete, il.get_TrxName());

		//Inserting a new tax

		//Exit if TaxAmt is 0
		//if (TaxAmt.equals(Env.ZERO)) //edited by ARH no need of this code because in case of zero tax we should update tax amount
			//return null;
		
		String sql = "SELECT COUNT(*) FROM C_TAX " +
				"WHERE Parent_Tax_Id = ?";
		int IsParent = DB.getSQLValue(il.get_TrxName(), sql, TaxId);

		

		if (IsParent == 0) // It has No Childs
		{
			//Inserting new records
			X_INS_INVOICETAX InvoiceTax = new X_INS_INVOICETAX(il.getCtx(), null, il.get_TrxName());
			InvoiceTax.setC_Invoice_ID(il.getC_Invoice_ID());
			InvoiceTax.setC_InvoiceLine_ID(il.getC_InvoiceLine_ID());
			InvoiceTax.setC_Tax_ID(TaxId);
			InvoiceTax.setTaxAmt( TaxAmt );

			InvoiceTax.save();
			
			//Update C_OrderLine
			
			String sqlUpdateOrderLine = "UPDATE C_InvoiceLine SET C_Tax_Id1=" + TaxId +
					", TaxPer1=" + il.getC_Tax().getRate() +
					", TaxAmt1=" + TaxAmt +
					", C_Tax_Id2= null"  +
					", TaxPer2= null"  +
					", TaxAmt2= 0"  +
					", C_Tax_Id3= null" +
					", TaxPer3= null"  +
					", TaxAmt3= 0"  +
					" WHERE C_InvoiceLine_Id=" + il.getC_InvoiceLine_ID();

			DB.executeUpdate(sqlUpdateOrderLine, il.get_TrxName());

			
		}		

		else // Tax is Parent
		{
			String sqlParent = "Select  T.C_Tax_Id, T.Rate " +
							"From C_Tax T " +
							"Where Parent_Tax_Id=?" +
							"Order By T.Rate Desc";

			PreparedStatement pstmt = null;
			ResultSet rs = null;
			try
			{
				pstmt = DB.prepareStatement(sqlParent, il.get_TrxName());
				
				pstmt.setInt(1, TaxId);
				rs = pstmt.executeQuery();
				int Counter = 0;
				while (rs.next())
				{
					Counter ++;
					
					//BigDecimal PaymentTotal = rs.getBigDecimal(1);		//	Total Payment Amount
					MTax m_tax = new MTax(ctx, TaxId, il.get_TrxName());
					BigDecimal TotalTaxPercent = m_tax.getRate();
					BigDecimal ThisTaxRate	= (BigDecimal) rs.getBigDecimal(2);
					BigDecimal ThisTaxRatio = ThisTaxRate.divide(TotalTaxPercent, 2, RoundingMode.HALF_UP);
					BigDecimal ThisTaxAmount = TaxAmt.multiply(ThisTaxRatio);
					int thisTaxId = rs.getInt(1);

					//Inserting new records
					X_INS_INVOICETAX InvoiceTax = new X_INS_INVOICETAX(il.getCtx(), null, il.get_TrxName());
					InvoiceTax.setC_Invoice_ID(il.getC_Invoice_ID());
					InvoiceTax.setC_InvoiceLine_ID(il.getC_InvoiceLine_ID());
					InvoiceTax.setC_Tax_ID(rs.getInt(1));
					InvoiceTax.setTaxAmt( ThisTaxAmount );
					InvoiceTax.save();
					
					//Update C_OrderLine
					//This will crash if there are more than 3 taxes therefore just updating first 3 taxes in C_OrderLine
					if (Counter <=3)
					{
						String sqlUpdateOrderLine = "UPDATE C_InvoiceLine SET " +
						"C_Tax_Id" + Counter + "=" + thisTaxId +
						", TaxPer" + Counter + "=" + ThisTaxRate +
						", TaxAmt" + Counter + "=" + ThisTaxAmount +
						" WHERE C_InvoiceLine_Id=" + il.getC_InvoiceLine_ID();

				DB.executeUpdate(sqlUpdateOrderLine, il.get_TrxName());
					
					}
					
				} //while
				
			} //try
		
				catch (SQLException e)
				{
					log.log(Level.SEVERE, sqlParent, e);
					return null;
				} //catch
				finally
				{
					DB.close(rs, pstmt);
					rs = null; pstmt = null;
				}//finally							
		
		
						
		} //else if	

		return null;
		
	} //Method
	
	public String deleteInvoiceLineZero(Properties ctx, MInvoiceLine il)
	{

		int TaxId = il.getC_Tax_ID();
		if (TaxId != 0) {return null;}
		
		//Delete lines with zero qty, amount and tax at the same time	
		String sqlDelete = "DELETE C_InvoiceLine " +
				"WHERE C_Tax_ID is null and LineNetAmt = 0 and QtyEntered = 0 and C_InvoiceLine_Id=" + il.getC_InvoiceLine_ID();
		
		DB.executeUpdate(sqlDelete, il.get_TrxName());
		
		il.save();
			
		return null;
		
	} //Method
	
} //Class